package com.cloudbroker.bcs.common.util;

import com.cloudbroker.bcs.common.model.PageArticle;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.safety.Whitelist;

import java.io.IOException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.*;

/**
 * Created by xuyn15828 on 2016/3/17.
 */
public class HtmlUtil {
    private static List<PageArticle> articleList = new ArrayList<>();

    private static int index = 0;

    public static void main(String[] args) throws IOException {
        //support
        // String url = "http://news.163.com/16/0317/09/BIBOT6RG00014JB5.html";

        String url = "http://finance.huanqiu.com/roll/2016-03/8752349.html";
        parseArticle(url);
    }

    public static Document clean(Document document) {
        return clean(document , Whitelist.relaxed());
    }

    public static Document clean(Document document , Whitelist list) {
        Document doc = Jsoup.parseBodyFragment(Jsoup.clean(document.html() , list));
        return doc;
    }

    public static void parseArticle(String url) throws IOException {
        LinkedList<String> urlList = new LinkedList<>();
        urlList.add(url);
        while( articleList.size() != 100 ) {
            PageArticle article = parseHtml(urlList.removeFirst());
            if( !articleList.contains(article) && article.getSummary().length() > 50 ) {
                System.out.println( article );
                articleList.add(article);
                urlList.addAll(article.getUrlList());
            }
        }
    }



    private static PageArticle parseHtml(String url) throws IOException {
        try {
            Document doc = Jsoup.connect(url).get();
            PageArticle article = setTitle(new PageArticle(), doc);
            doc = clean(doc);
            Element titleElement = findElementByText(article.getTitle(), doc.body());
            article = setSummary(article, doc, titleElement);
            article = setImgUrl(article, doc, titleElement);
            article = setUrl(article, doc, titleElement, url);
            return article;
        }catch ( SocketTimeoutException e) {
            return parseHtml(url);
        }
    }

    private static PageArticle setUrl(PageArticle article, Document doc , Element titleElement , String url) {
        String bakUrl = url;
        List<Element> aList = new ArrayList<>();
        findElementByPosition(doc.body() , titleElement , true , true , aList , new HashSet<>(Arrays.asList("a")));
        if( null == aList || 0 == aList.size() ) {
            article.setUrlList(null);
        }
        Element currentA = null;
        for(int i = 0 ; i < aList.size() ; i++) {
            currentA = aList.get(i);
            String bakHref = currentA.attr("href");
            String[] netProcol = new String[]{"http://" , "https://"};
            for (String procol : netProcol) {
                url = bakUrl;
                String href = bakHref;
                if (url.startsWith(procol) && href.startsWith(procol)) {
                    url = url.substring(procol.length());
                    href = href.substring(procol.length());
                    if (url.split("/").length == href.split("/").length) {
                        if( -1 != url.lastIndexOf(".")  && url.substring(url.lastIndexOf(".")).equals(href.substring(href.lastIndexOf("."))) ) {
                            article.getUrlList().add( currentA.attr("href") );
                        }

                    }
                }
            }
        }
        return article;
    }

    private static PageArticle setImgUrl(PageArticle article, Document doc, Element titleElement) {
        List<Element> imgList = new ArrayList<>();
        findElementByPosition(doc.body() , titleElement , false , true , imgList , new HashSet<>(Arrays.asList("img")));
        if( null == imgList || 0 == imgList.size() ) {
            article.setImgUrl(null);
        }
        Element currentImg = null;
        for(int i = 0 ; i < imgList.size() ; i++) {
            currentImg = imgList.get(i);
            if( currentImg.hasAttr("alt") ) {
                if( currentImg.attr("alt").equals(article.getTitle()) ) {
                    article.setImgUrl(currentImg.attr("src"));
                    return article;
                }
                imgList.remove(currentImg);
                continue;
            }
            if( currentImg.hasAttr("width") ) {
                List<String> strList = RegexUtil.extractNumber(currentImg.attr("width"),null);
                if( strList.size() != 0 ) {
                    Integer width = Integer.parseInt(strList.get(0));
                    if (width < 25) {
                        imgList.remove(currentImg);
                        continue;
                    }
                }
            }
            if( currentImg.hasAttr("height") ) {
                List<String> strList = RegexUtil.extractNumber(currentImg.attr("height"),null);
                if( strList.size() != 0 ) {
                    Integer height = Integer.parseInt(strList.get(0));
                    if (height < 25) {
                        imgList.remove(currentImg);
                        continue;
                    }
                }
            }
        }
        if( 0 == imgList.size() ) {
            article.setImgUrl(null);
        } else {
            article.setImgUrl(imgList.get(0).attr("src"));
        }
        return article;
    }

    private static PageArticle setSummary(PageArticle article, Document doc, Element titleElement) {
        List<Element> articleList = new ArrayList<>();
        findElementByPosition(doc.body() , titleElement , false , true , articleList , new HashSet<>(Arrays.asList("p" , "article" , "dd" , "span")));
        StringBuffer summaryBuffer = new StringBuffer();
        for (Element element : articleList) {
            if( 0 != element.children().size() || element.ownText().length() < 25 ) {
                continue;
            }
            summaryBuffer.append( element.ownText() ).append("\n");
        }
        article.setSummary(summaryBuffer.toString());
        return article;
    }

    /**
     * 查询整篇文档中,以Element为参照,查找之前或之后的标签名在tagNames之中的标签
     * */
    private static void findElementByPosition(Element parentElement , Element position ,
                                                      boolean before , boolean after, List<Element> resultList,
                                                       Set<String> tagNames) {
        if( null == resultList ) {
            resultList = new ArrayList<>();
        }
        if( null ==tagNames || 0 == tagNames.size() ) {
            return ;
        }
        if( !before && !after ) {
            return;
        }
        for(Element element : parentElement.children() ) {
            if( element.equals(position) ) {
                before = false;
            }
            if( before || after && tagNames.contains(element.tagName()) ) {
                resultList.add(element);
            }
            findElementByPosition(element , position , before , after , resultList , tagNames);
        }
    }

    private static Element findElementByText(String text, Element parentElement) {
        for(Element element : parentElement.children() ) {
            if( element.ownText().equals(text) ) {
                return element;
            }
            Element resultElement = findElementByText(text , element);
            if( resultElement != null ) {
                return resultElement;
            }
        }
        return null;
    }

    private static String getText(Element element) {
        if( null == element )
            return StringUtil.EMPTY_STRING;
        return element.ownText();
    }

    private static PageArticle setTitle(PageArticle pageArticle, Document doc) {
        String title = doc.title();
        int indexOf = -1;
        if( (indexOf = title.indexOf("_")) != -1 ) {
            title = title.substring(0, indexOf);
        } else if( (indexOf = title.indexOf("-")) != -1 ) {
            title = title.substring(0, indexOf);
        }
        pageArticle.setTitle(title);
        return pageArticle;
    }
}
